use crate::{client::RedisClient, resp::Command, RedisResult};

impl RedisClient {
    pub async fn set_sadd(&self, key: &str, value: impl Into<String>) -> RedisResult<usize> {
        let cmd = Command::new_with_key("SET", key).arg(value.into());
        self.send_command(cmd).await
    }

    pub async fn set_sadd_more(&self, key: &str, values: &[&str]) -> RedisResult<usize> {
        let mut cmd: Command<'_> = Command::new_with_key("SET", key);
        for value in values {
            cmd.arg_append(*value);
        }
        self.send_command(cmd).await
    }

    pub async fn set_scard(&self, key: &str) -> RedisResult<usize> {
        let cmd = Command::new_with_key("SCARD", key);
        self.send_command(cmd).await
    }

    pub async fn set_sdiff(&self, keys: &[&str]) -> RedisResult<Vec<String>> {
        let cmd = Command::new_with_keys("SDIFF", keys);
        self.send_command(cmd).await
    }

    pub async fn set_sdiffstore(&self, key_destination: &str, keys: &[&str]) -> RedisResult<usize> {
        let cmd = Command::new_with_key_and_keys("SDIFF", key_destination, keys);
        self.send_command(cmd).await
    }

    pub async fn set_sinter(&self, keys: &[&str]) -> RedisResult<usize> {
        let mut cmd = Command::new_with_keys("SINTER", keys);
        for item in keys.iter() {
            cmd.arg_append(*item);
        }
        self.send_command(cmd).await
    }

    pub async fn set_interstore(&self, key_destination: &str, keys: &[&str]) -> RedisResult<usize> {
        let cmd = Command::new_with_key_and_keys("SINTERSTORE", key_destination, keys);
        self.send_command(cmd).await
    }

    pub async fn set_sismember(&self, key: &str, member: &str) -> RedisResult<bool> {
        let cmd = Command::new_with_key("SISMEMBER", key).arg(member);
        Ok(self.send_command::<isize>(cmd).await? == 1)
    }

    pub async fn set_smembers(&self, key: &str) -> RedisResult<Vec<String>> {
        let cmd = Command::new_with_key("SMEMBERS", key);
        self.send_command(cmd).await
    }

    pub async fn set_smismember(&self, key: &str, members: &[&str]) -> RedisResult<Vec<bool>> {
        let mut cmd = Command::new_with_key("SMISMEMBER", key);
        for member in members {
            cmd.arg_append(*member);
        }
        let res = self.send_command::<Vec<isize>>(cmd).await?;
        Ok(res.into_iter().map(|x| x == 1).collect())
    }

    pub async fn set_smove(
        &self,
        key_source: &str,
        key_destination: &str,
        member: &str,
    ) -> RedisResult<bool> {
        let keys = &[key_source, key_destination];
        let cmd = Command::new_with_keys("SMOVE", keys).arg(member);
        Ok(self.send_command::<isize>(cmd).await? == 1)
    }

    pub async fn set_spop(&self, key: &str) -> RedisResult<Option<Vec<u8>>> {
        let cmd = Command::new_with_key("SPOP", key);
        self.send_command(cmd).await
    }

    pub async fn set_spop_count(
        &self,
        key: &str,
        count: usize,
    ) -> RedisResult<Option<Vec<Vec<u8>>>> {
        let cmd = Command::new_with_key("SPOP", key).arg(count);
        self.send_command(cmd).await
    }

    pub async fn set_srandmember(&self, key: &str) -> RedisResult<Option<Vec<u8>>> {
        let cmd = Command::new_with_key("SRANDMEMBER", key);
        self.send_command(cmd).await
    }

    pub async fn set_srandmember_count(
        &self,
        key: &str,
        count: usize,
    ) -> RedisResult<Option<Vec<Vec<u8>>>> {
        let cmd = Command::new_with_key("SRANDMEMBER", key).arg(count);
        self.send_command(cmd).await
    }

    pub async fn set_srem(&self, key: &str, member: &str) -> RedisResult<usize> {
        let cmd = Command::new_with_key("SREM", key).arg(member);
        self.send_command(cmd).await
    }

    pub async fn set_srem_more(&self, key: &str, members: &[&str]) -> RedisResult<usize> {
        let mut cmd = Command::new_with_key("SREM", key);
        for member in members {
            cmd.arg_append(*member);
        }
        self.send_command(cmd).await
    }

    pub async fn set_sunion(&self, keys: &[&str]) -> RedisResult<Vec<Vec<u8>>> {
        let cmd = Command::new_with_keys("SUNION", keys);
        self.send_command(cmd).await
    }

    pub async fn set_sunionstore(
        &self,
        key_destination: &str,
        keys: &[&str],
    ) -> RedisResult<usize> {
        if keys.len() == 0 {
            return Err(crate::RedisError::CommandFormat(
                "the len of [keys] shouldn't be 0".to_string(),
            ));
        }
        let cmd = Command::new_with_key_and_keys("SUNIONSTORE", key_destination, keys);
        self.send_command(cmd).await
    }
}
